package org.tinygroup.parsedsql.parser;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import org.tinygroup.logger.LogLevel;
import org.tinygroup.logger.Logger;
import org.tinygroup.logger.LoggerFactory;

public class VisitorHandler implements MethodInterceptor {

	private static final Logger LOGGER = LoggerFactory
			.getLogger(VisitorHandler.class);

	private final StringBuilder hierarchyIndex = new StringBuilder();

	private Integer depth = 0;

	public Object intercept(final Object enhancedObject, final Method method,
			final Object[] arguments, final MethodProxy methodProxy)
			throws Throwable {
		if (isPrintable(method)) {
			hierarchyIn();
			LOGGER.traceMessage("{0} visit node: {1}", hierarchyIndex,
					arguments[0].getClass());
			LOGGER.traceMessage("{0} visit argument: {1}", hierarchyIndex,
					arguments[0]);
		}
		Object result = methodProxy.invokeSuper(enhancedObject, arguments);
		if (isPrintable(method)) {
			SQLVisitor visitor = (SQLVisitor) enhancedObject;
			LOGGER.traceMessage("{0} endVisit node: {1}", hierarchyIndex,
					arguments[0].getClass());
			LOGGER.traceMessage("{0} endVisit SQL: {1}", hierarchyIndex,
					visitor.getSQLBuilder());
			hierarchyOut();
		}
		return result;
	}

	private boolean isPrintable(final Method method) {
		return LOGGER.isEnabled(LogLevel.TRACE)
				&& "visit".equals(method.getName());
	}

	private void hierarchyIn() {
		hierarchyIndex.append("  ").append(++depth).append(" ");
	}

	private void hierarchyOut() {
		hierarchyIndex.delete(hierarchyIndex.length() - 3
				- depth.toString().length(), hierarchyIndex.length());
		depth--;
	}
}